package com.bestv.search.engine.command;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.TopNCache;
import com.bestv.search.common.service.TopNCacheManager;
import com.bestv.search.common.util.StringConst;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Michael Wang
 */
public class TopNCacheCommand {

    private static final int DEFAULT_INFOS_TOPN_LIMIT = 50;
    private static final int DEFAULT_INFOS_INCREASE_TOPN_LIMIT = 20;
    private static final int DEFAULT_KEYWORDS_TOPN_LIMIT = 50;
    private static final int DEFAULT_KEYWORDS_INCREASE_TOPN_LIMIT = 20;
    private static ReentrantLock lock = new ReentrantLock();
    private static Log log = LogFactory.getLog(TopNCacheCommand.class);
    private static boolean isRunning = false;
    private static Map<String, List<TopNCache>> keywordsCache = new HashMap<String, List<TopNCache>>();
    private static Map<String, List<TopNCache>> infosCache = new HashMap<String, List<TopNCache>>();

    private final String[] allCategorys = new String[]{"全部", "电影", "电视剧", "少儿", "体育", "凤凰", "娱乐", "新闻", "时尚生活", "法治",
            "纪实", "财经", "音乐"};

    private SystemCache systemCache;
    private TopNCacheManager topNCacheManager;

    public boolean updateMemoryCache() {
        if (!isRunning) {
            try {
                isRunning = true;
                // Update Keywords Memory Cache
                updateMemoryCache(keywordsCache, StringConst.KEYWORD, null, DEFAULT_KEYWORDS_TOPN_LIMIT,
                        DEFAULT_KEYWORDS_INCREASE_TOPN_LIMIT);

                // Update Infos Memory Cache
                for (String category : allCategorys) {
                    updateMemoryCache(infosCache, StringConst.INFO, category, DEFAULT_INFOS_TOPN_LIMIT,
                            DEFAULT_INFOS_INCREASE_TOPN_LIMIT);
                }
            } catch (Exception e) {
                log.info(" Update topn cache faile, due to exception ");
                e.printStackTrace();
            } finally {
                isRunning = false;
            }
            return true;
        } else {
            log.info(" Last process is running, please wait... ");
            return false;
        }
    }

    public List<TopNCache> getTopNListFromCache(String cacheType, String type, boolean increase, String category) {
        if (keywordsCache.size() == 0 || infosCache.size() == 0) {
            if (!updateMemoryCache()) {
                return new ArrayList<TopNCache>();
            }
        }

        String cacheKey = null;
        if (increase) {
            cacheKey = cacheType + type + (category == null ? StringConst.EMPTY : category) + StringConst.INCREASE;
        } else {
            cacheKey = cacheType + type + (category == null ? StringConst.EMPTY : category);
        }

        List<TopNCache> result = null;
        if (StringConst.KEYWORD.equals(cacheType)) {
            result = keywordsCache.get(cacheKey.toLowerCase());
        } else {
            result = infosCache.get(cacheKey.toLowerCase());
        }

        if (result == null) {
            log.error(" Invalid key " + cacheKey.toLowerCase() + " to get infos from topNCache. ");
        }

        return result;
    }

    public void removeOfflineInfosFromMemoryCache(Set<String> codes) {
        for (String code : codes) {
            for (List<TopNCache> infos : infosCache.values()) {
                for (TopNCache info : infos) {
                    String codeInMemoryCache = info.getCode();
                    if (codeInMemoryCache != null && codeInMemoryCache.equals(code)) {
                        infos.remove(info);
                        break;
                    }
                }
            }
        }
    }

    private void updateMemoryCache(Map<String, List<TopNCache>> memoryCache, String cacheType, String category,
                                   int topN, int increaseTopN) {
        DataSourceKey key = DataSourceKeyUtil.convert(systemCache.getLocalDataSourceKey());

        // Daily
        List<TopNCache> list = topNCacheManager.get(key, StringConst.DAILY, cacheType, category, topN);
        String cacheKey = cacheType + StringConst.DAILY + (category == null ? StringConst.EMPTY : category);
        updateMemoryCache(memoryCache, cacheKey, list);

        // week
        list = topNCacheManager.get(key, StringConst.WEEKLY, cacheType, category, topN);
        cacheKey = cacheType + StringConst.WEEKLY + (category == null ? StringConst.EMPTY : category);
        updateMemoryCache(memoryCache, cacheKey, list);

        // Month
        list = topNCacheManager.get(key, StringConst.MONTHLY, cacheType, category, topN);
        cacheKey = cacheType + StringConst.MONTHLY + (category == null ? StringConst.EMPTY : category);
        updateMemoryCache(memoryCache, cacheKey, list);

        // Quarter
        list = topNCacheManager.get(key, StringConst.QUARTER, cacheType, category, topN);
        cacheKey = cacheType + StringConst.QUARTER + (category == null ? StringConst.EMPTY : category);
        updateMemoryCache(memoryCache, cacheKey, list);

        // Total
        list = topNCacheManager.get(key, StringConst.TOTAL, cacheType, category, topN);
        cacheKey = cacheType + StringConst.TOTAL + (category == null ? StringConst.EMPTY : category);
        updateMemoryCache(memoryCache, cacheKey, list);

        // Daily Increase
        list = topNCacheManager.getIncrease(key, StringConst.DAILY, cacheType, category, increaseTopN);
        cacheKey = cacheType + StringConst.DAILY + (category == null ? StringConst.EMPTY : category)
                + StringConst.INCREASE;
        updateMemoryCache(memoryCache, cacheKey, list);

        // week Increase
        list = topNCacheManager.getIncrease(key, StringConst.WEEKLY, cacheType, category, increaseTopN);
        cacheKey = cacheType + StringConst.WEEKLY + (category == null ? StringConst.EMPTY : category)
                + StringConst.INCREASE;
        updateMemoryCache(memoryCache, cacheKey, list);

        // Month Increase
        list = topNCacheManager.getIncrease(key, StringConst.MONTHLY, cacheType, category, increaseTopN);
        cacheKey = cacheType + StringConst.MONTHLY + (category == null ? StringConst.EMPTY : category)
                + StringConst.INCREASE;
        updateMemoryCache(memoryCache, cacheKey, list);

        // Quarter Increase
        list = topNCacheManager.getIncrease(key, StringConst.QUARTER, cacheType, category, increaseTopN);
        cacheKey = cacheType + StringConst.QUARTER + (category == null ? StringConst.EMPTY : category)
                + StringConst.INCREASE;
        updateMemoryCache(memoryCache, cacheKey, list);
    }

    private void updateMemoryCache(Map<String, List<TopNCache>> memoryCache, String key, List<TopNCache> value) {
        try {
            lock.lock();
            memoryCache.put(key.toLowerCase(), value);
        } catch (Exception e) {
            log.error("Update topInfoCache failed " + key);
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public TopNCacheManager getTopNCacheManager() {
        return topNCacheManager;
    }

    public void setTopNCacheManager(TopNCacheManager topNCacheManager) {
        this.topNCacheManager = topNCacheManager;
    }

    public SystemCache getSystemCache() {
        return systemCache;
    }

    public void setSystemCache(SystemCache systemCache) {
        this.systemCache = systemCache;
    }
}
